]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
extensions: Add static defineTranslationFunctions() method
authorFlorian Müllner <fmuellner@gnome.org>
Mon, 10 Jul 2023 05:06:17 +0000 (07:06 +0200)
committerFlorian Müllner <fmuellner@gnome.org>
Sun, 30 Jul 2023 07:29:44 +0000 (10:29 +0300)
The method can be used to define a set of gettext functions that
call the corresponding method of an extension.

Those functions are very similar to the gettext functions we are
exporting, except that:

 - looking up the extension is delegated to the
   Extension/Preferences class
 - it is possible to avoid examining the stack
   when called with `import.meta.url`

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2838>

js/extensions/extension.js
js/extensions/prefs.js
js/extensions/sharedInternals.js

index 56f11fa637e2630d9dbf9b3a0afbdecb92acf8c9..966a8336bd5a5a04a4183e1d954bc4360a238b88 100644 (file)
@@ -1,4 +1,4 @@
-import {ExtensionBase, setExtensionManager} from './sharedInternals.js';
+import {ExtensionBase, GettextWrapper, setExtensionManager} from './sharedInternals.js';
 
 export {gettext, ngettext, pgettext} from './sharedInternals.js';
 
@@ -6,6 +6,11 @@ const {extensionManager} = imports.ui.main;
 setExtensionManager(extensionManager);
 
 export class Extension extends ExtensionBase {
+    static defineTranslationFunctions(url) {
+        const wrapper = new GettextWrapper(this, url);
+        return wrapper.defineTranslationFunctions();
+    }
+
     enable() {
     }
 
index 49c72d84a133cce4b0a3fc63ec75127d971cffa2..db285e247c3abfcfd780e6ba8138051a5014f5cd 100644 (file)
@@ -1,6 +1,6 @@
 import GObject from 'gi://GObject';
 
-import {ExtensionBase, setExtensionManager} from './sharedInternals.js';
+import {ExtensionBase, GettextWrapper, setExtensionManager} from './sharedInternals.js';
 import {extensionManager} from '../extensionsService.js';
 
 setExtensionManager(extensionManager);
@@ -8,6 +8,11 @@ setExtensionManager(extensionManager);
 export {gettext, ngettext, pgettext} from './sharedInternals.js';
 
 export class ExtensionPreferences extends ExtensionBase {
+    static defineTranslationFunctions(url) {
+        const wrapper = new GettextWrapper(this, url);
+        return wrapper.defineTranslationFunctions();
+    }
+
     /**
      * Fill the preferences window with preferences.
      *
index 8ec152332e25b7ca9223e88cee7d5b72a5b143df..2d5afd0f6644497c5dda2339ec8b16f35184fab0 100644 (file)
@@ -184,6 +184,99 @@ export class ExtensionBase {
     }
 }
 
+export class GettextWrapper {
+    #url;
+    #extensionClass;
+
+    constructor(extensionClass, url) {
+        this.#url = url;
+        this.#extensionClass = extensionClass;
+    }
+
+    #detectUrl() {
+        const basePath = '/gnome-shell/extensions/';
+
+        // Search for an occurrence of an extension stack frame
+        // Start at 1 because 0 is the stack frame of this function
+        const [, ...stack] = new Error().stack.split('\n');
+        const extensionLine = stack.find(
+            line => line.includes(basePath));
+
+        if (!extensionLine)
+            return null;
+
+        // The exact stack line differs depending on where the function
+        // was called (function or module scope), and whether it's called
+        // from a module or legacy import (file:// URI vs. plain path).
+        //
+        // We don't have to care about the exact composition, all we need
+        // is a string that can be traversed as path and contains the UUID
+        const path = extensionLine.slice(extensionLine.indexOf(basePath));
+        return `file://${path}`;
+    }
+
+    #lookupExtension(funcName) {
+        if (!this.#url)
+            this.#url = this.#detectUrl();
+
+        const extension = this.#extensionClass.lookupByURL(this.#url);
+        if (!extension)
+            throw new Error(`${funcName} can only be called from extensions`);
+        return extension;
+    }
+
+    #gettext(str) {
+        const extension = this.#lookupExtension('gettext');
+        return extension.gettext(str);
+    }
+
+    #ngettext(str, strPlural, n) {
+        const extension = this.#lookupExtension('ngettext');
+        return extension.gettext(str, strPlural, n);
+    }
+
+    #pgettext(context, str) {
+        const extension = this.#lookupExtension('pgettext');
+        return extension.pgettext(context, str);
+    }
+
+    defineTranslationFunctions() {
+        return {
+            /**
+             * Translate `str` using the extension's gettext domain
+             *
+             * @param {string} str - the string to translate
+             *
+             * @returns {string} the translated string
+             */
+            gettext: this.#gettext.bind(this),
+
+            /**
+             * Translate `str` and choose plural form using the extension's
+             * gettext domain
+             *
+             * @param {string} str - the string to translate
+             * @param {string} strPlural - the plural form of the string
+             * @param {number} n - the quantity for which translation is needed
+             *
+             * @returns {string} the translated string
+             */
+            ngettext: this.#ngettext.bind(this),
+
+            /**
+             * Translate `str` in the context of `context` using the extension's
+             * gettext domain
+             *
+             * @param {string} context - context to disambiguate `str`
+             * @param {string} str - the string to translate
+             *
+             * @returns {string} the translated string
+             */
+            pgettext: this.#pgettext.bind(this),
+        };
+    }
+}
+
 /**
  * @private
  *